package com.googlecode.dgwt.client.dojox.data.model;

import com.googlecode.dgwt.client.dojo.Dojo;
import com.googlecode.dgwt.client.dojo.data.format.ValueFormatter;
import com.googlecode.dgwt.client.dojo.data.model.ModelAttachException;
import com.googlecode.dgwt.client.dojo.data.model.StoreModel;
import com.googlecode.dgwt.client.dojo.exception.AttachException;
import com.googlecode.dgwt.client.dojo.reflect.BeanField;
import com.googlecode.dgwt.client.dojo.reflect.BeanInfo;
import com.googlecode.dgwt.client.dojo.reflect.BeanMethod;
import com.googlecode.dgwt.client.dojo.reflect.HasBeanInfo;
import com.googlecode.dgwt.client.dojox.data.model.base.DataColumnBase;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class BeanColumn<Item> extends DataColumnBase<Item, Object> {

    private BeanField<Item> beanField = Dojo.reflect.<Item>getEmptyMethodInfo();
        
    
    public BeanColumn(String name) {
        super();
        setName(name);
    }

    public BeanColumn(String name, String title) {
        super(title);
        setName(name);
    }

    public BeanColumn(String name, int maxLength) {
        super(maxLength);
        setName(name);
    }

    public BeanColumn(String name, ValueFormatter<Item> formatter) {
        super(formatter);
        setName(name);
    }

    public BeanColumn(String name, String title, int maxLength) {
        super(title, maxLength);
        setName(name);
    }

    public BeanColumn(String name, String title, ValueFormatter<?> formatter) {
        super(title, formatter);
        setName(name);
    }

    public BeanColumn(String name, String title, int maxLength, ValueFormatter<?> formatter) {
        super(title, maxLength, formatter);
        setName(name);
    }

    
    @SuppressWarnings("unchecked")
    protected BeanInfo<Item> getBeanInfo(){
        return ((HasBeanInfo<Item>) super.getModel()).getBeanInfo();
    }
    
    
    @Override
    public void onAttach(StoreModel<Item, ?> model) throws AttachException {
        if (!(model instanceof HasBeanInfo<?>)) {
            throw new ModelAttachException(getClass(), BeanModel.class);
        }
        super.onAttach(model);        
        setBeanField(getBeanInfo().getFields().get(getName()));
    }

    
    @Override
    public void onDetach(StoreModel<Item, ?> model) {
        super.onDetach(model);
        setBeanField(null);
    }
    
    
    @Override
    public void setName(String name) {
        if (isModelAttached()) {
            if (name == null) {
                name = "";
            }
            if (!getName().equals(name)) {
                setBeanField(getBeanInfo().getFields().get(name));
            }
        }
        super.setName(name);
    }
    

    protected void setBeanField(BeanField<Item> beanField) {
        if (beanField == null) {
            this.beanField = Dojo.reflect.getEmptyMethodInfo();
        } else {
            this.beanField = beanField;
        }
        updateFormatter();
    }

    
    protected BeanField<Item> getBeanField() {
        return beanField;
    }


    @Override
    public Object onGetValue(Item item) {
        if (beanField.getGetter() != null) {
            return beanField.getGetter().call(item);
        }
        return null;
    }

    @Override
    public void onSetValue(Item item, Object value) {
        if (beanField.getSetter() != null && !isReadOnly()) {
            beanField.getSetter().call(item, value);
            onItemValueModified(item);
        }
    }

    @Override
    public Class<?> getColumnType() {
        BeanMethod<Item> method = getBeanField().getSetter();
        if (method != null) {
            return method.getParams().get(0).getType();
        }
        return beanField.getGetter().getReturnType();
    }

}
